/* JavaLog - package tracker 
 * 
 * Copyright (C) 2009  Allyson Lima, Diego Pedro, Victor Freire
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software 
 * Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this 
 * program.  If not, see <http://www.gnu.org/licenses/>.
 */

package br.edu.ufcg.ccc.javalog.model;

import java.util.UUID;

import br.edu.ufcg.ccc.javalog.comments.PossibleImprovement;
import br.edu.ufcg.ccc.javalog.exceptions.UserNullPointerException;

/**
 * Validation class.
 * 
 * @author Allyson Lima, Diego Pedro, Victor Freire
 * @version 08/11/09
 */
public class Validator {

	/**
	 * Validates an exception passed to the validator.
	 * 
	 * @param exception
	 *            exception to throw on error
	 * @throws IllegalArgumentException
	 *             when a null exception is received
	 * 
	 */
	private static <E extends Exception> void validateException(E exception) {
		if (exception == null)
			throw new UserNullPointerException("passed a null exception to validator");
	}

	/**
	 * Checks if the object is null. This method DOES NOT VALIDATE THE EXCEPTION
	 * and as such it is meant for internal use only.
	 * 
	 * @param obj
	 *            object to test
	 * @param exception
	 *            exception to throw on error
	 * @throws IllegalArgumentException
	 *             when a null exception is received
	 */
	@SuppressWarnings("unused")
	private static <E extends Exception> void validateObjectOnly(Object obj,
			E exception) throws E {
		if (obj == null) throw new UserNullPointerException(exception);
	}

	/**
	 * Checks if the object is null. This is the most generic object validation
	 * available.
	 * 
	 * @param obj
	 *            object to test
	 * @param exception
	 *            exception to throw on error
	 * @throws IllegalArgumentException
	 *             when a null exception is received
	 */
	public static <E extends Exception> void validateObject(Object obj,
			E exception) throws E {
		Validator.validateException(exception);
		if (obj == null) throw new UserNullPointerException(exception);
	}

	/**
	 * Checks if the String is null or empty. Leading and trailing whitespaces
	 * are removed when checking for emptiness.
	 * 
	 * @param str
	 *            string to test
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception thrown if the test fails
	 */
	public static <E extends Exception> void validateString(String str,
			E exception) throws E {
		validateObject(str, exception);
		if (str.trim().isEmpty())
			throw exception;

	}

	/**
	 * Checks if the String is a natural language phrase. Calls validateString()
	 * then tests for invalid characters.
	 * 
	 * @param phr
	 *            phrase to test
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception thrown if the test fails
	 */
	public static <E extends Exception> void validatePhrase(String phr,
			E exception) throws E {
		validateString(phr, exception);
		// TODO validatePhrase() - check for invalid characters?
	}

	/**
	 * Checks if the address number is valid.
	 * 
	 * @param addrNumber
	 *            addrNumber
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception thrown if the test fails
	 */
	@PossibleImprovement(author = "Victor Freire", 
						date = "07/11/09", 
						description = "Add additional checks to this method.")
	public static <E extends Exception> void validateAddressNumber(
			String addrNumber, E exception) throws E {
		if (addrNumber.trim().charAt(0) == '-')
			throw exception;
	}

	/**
	 * Checks if the geographical coordinate is valid.
	 * 
	 * @param coordinate
	 *            latitude or longitude
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception throw if the test fails
	 */
	public static <E extends Exception> void validateGeographicalPositionFormat(
			String coordinate, E exception) throws E {

		String locationSplit[] = coordinate.split(":");

		if (locationSplit.length < 3 || locationSplit.length > 3)
			throw exception;

		try {
			for (int i = 0; i < 3; i++)
				Integer.parseInt(locationSplit[i]);
		} catch (NumberFormatException ex) {
			throw exception;
		}
	}

	/**
	 * Checks if the coordinates are in a valid range.
	 * 
	 * @param coordinate
	 *            latitude or longitude
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception throw if the test fails
	 */
	public static <E extends Exception> void validateGeographicalPositionLimit(
			String coordinate, E exception) throws E {

		String locationSplit[] = coordinate.split(":");

		if (Integer.parseInt(locationSplit[0]) < -90
				|| Integer.parseInt(locationSplit[0]) > 90)
			throw exception;

		for (int i = 1; i < 3; i++)
			if (Integer.parseInt(locationSplit[i]) < 0
					|| Integer.parseInt(locationSplit[0]) > 60)
				throw exception;
	}

	/**
	 * Checks if the package id is valid.
	 * 
	 * @param pid
	 *            package id to check
	 * @param exception
	 *            exception to throw on error
	 * @throws E
	 *             exception thrown if the test fails
	 */
	public static <E extends Exception> void validatePackageID(String pid,
			E exception) throws E {
		try {
			validateString(pid, exception);
			UUID.fromString(pid); // fails if the String provided is not a valid
		} catch (IllegalArgumentException e) {
			throw exception;
		}
	}

}
